
/**
 * zh-string.js
 * 中文字符串封装库
 */
 class 字符串 {
  /**
   * 创建一个新的 中文字符串 封装对象
   * @param {string|any} 内容 要包装的内容（自动 toString）
   */
  constructor(内容 = "") {
    /** @private {string} */
    this._值 = String(内容 ?? "");
  }

  // ===== 返回 / 输出 =====
  /**
   * 获取当前原始字符串值
   * @returns {string}
   */
  值() {
    return this._值;
  }

  /**
   * 返回字符串（兼容 toString）
   * @returns {string}
   */
  toString() {
    return this._值;
  }

  /**
   * 值化（兼容 valueOf）
   * @returns {string}
   */
  valueOf() {
    return this._值;
  }

  /**
   * 打印当前值（链式）
   * @returns {字符串}
   */
  打印() {
    console.log(this._值);
    return this;
  }

  // ===== 基本转换（链式返回 this） =====

  /**
   * 去掉首尾空白（trim）
   * @returns {字符串}
   */
  去空格() {
    this._值 = this._值.trim();
    return this;
  }

  /**
   * 去掉开头空白（trimStart / trimLeft）
   * @returns {字符串}
   */
  去前空格() {
    this._值 = this._值.trimStart ? this._值.trimStart() : this._值.trimLeft();
    return this;
  }

  /**
   * 去掉结尾空白（trimEnd / trimRight）
   * @returns {字符串}
   */
  去后空格() {
    this._值 = this._值.trimEnd ? this._值.trimEnd() : this._值.trimRight();
    return this;
  }

  /**
   * 全部转为大写
   * @returns {字符串}
   */
  大写() {
    this._值 = this._值.toUpperCase();
    return this;
  }

  /**
   * 全部转为小写
   * @returns {字符串}
   */
  小写() {
    this._值 = this._值.toLowerCase();
    return this;
  }

  /**
   * 仅首字母大写（其余保持不变）
   * @returns {字符串}
   */
  首字母大写() {
    if (this._值.length > 0) {
      this._值 = this._值.charAt(0).toUpperCase() + this._值.slice(1);
    }
    return this;
  }

  /**
   * 仅首字母小写（其余保持不变）
   * @returns {字符串}
   */
  首字母小写() {
    if (this._值.length > 0) {
      this._值 = this._值.charAt(0).toLowerCase() + this._值.slice(1);
    }
    return this;
  }

  /**
   * 反转字符串
   * @returns {字符串}
   */
  反转() {
    // 注意：对于代理代理 Unicode surrogate pair 可能不完美
    this._值 = Array.from(this._值).reverse().join("");
    return this;
  }

  /**
   * 重复字符串 n 次（repeat）
   * @param {number} 次数
   * @returns {字符串}
   */
  重复(次数) {
    this._值 = this._值.repeat(次数);
    return this;
  }

  /**
   * 拼接字符串（concat）
   * @param {...string} 内容
   * @returns {字符串}
   */
  拼接(...内容) {
    this._值 = this._值.concat(...内容);
    return this;
  }

  // ===== 检索 / 判断（返回原生类型） =====

  /**
   * 获取长度（length）
   * @returns {number}
   */
  取长度() {
    return this._值.length;
  }

  /**
   * 是否为空（长度为0）
   * @returns {boolean}
   */
  是否空() {
    return this._值.length === 0;
  }

  /**
   * 是否全部为空白（trim 后为空）
   * @returns {boolean}
   */
  是否空白() {
    return this._值.trim().length === 0;
  }

  /**
   * 查找子串（indexOf）
   * @param {string} 子串
   * @param {number} [起始=0]
   * @returns {number}
   */
  查找(子串, 起始 = 0) {
    return this._值.indexOf(子串, 起始);
  }

  /**
   * 反向查找（lastIndexOf）
   * @param {string} 子串
   * @param {number} [起始]
   * @returns {number}
   */
  反向查找(子串, 起始) {
    return this._值.lastIndexOf(子串, 起始);
  }

  /**
   * 是否包含（includes）
   * @param {string} 子串
   * @returns {boolean}
   */
  包含(子串) {
    return this._值.includes(子串);
  }

  /**
   * 是否以某前缀开始（startsWith）
   * @param {string} 前缀
   * @param {number} [起始=0]
   * @returns {boolean}
   */
  以开头(前缀, 起始 = 0) {
    return this._值.startsWith(前缀, 起始);
  }

  /**
   * 是否以某后缀结束（endsWith）
   * @param {string} 后缀
   * @param {number} [长度]
   * @returns {boolean}
   */
  以结尾(后缀, 长度) {
    return this._值.endsWith(后缀, 长度);
  }

  /**
   * 搜索正则（search）
   * @param {RegExp|string} 正则
   * @returns {number}
   */
  搜索(正则) {
    return this._值.search(正则);
  }

  /**
   * 本地比较（localeCompare）
   * @param {string} 目标
   * @param {string|string[]} [locales]
   * @param {Intl.CollatorOptions} [options]
   * @returns {number}
   */
  本地比较(目标, locales, options) {
    return this._值.localeCompare(目标, locales, options);
  }

  // ===== 正则 / 匹配 =====

  /**
   * 匹配（match）
   * @param {RegExp|string} 正则
   * @returns {RegExpMatchArray|null}
   */
  匹配(正则) {
    return this._值.match(正则);
  }

  /**
   * 匹配所有（matchAll）
   * @param {RegExp} 正则
   * @returns {IterableIterator<RegExpMatchArray>}
   */
  匹配所有(正则) {
    return this._值.matchAll(正则);
  }

  /**
   * 匹配所有并返回数组（方便使用）
   * @param {RegExp} 正则
   * @returns {Array<RegExpMatchArray>}
   */
  匹配所有数组(正则) {
    return Array.from(this._值.matchAll(正则));
  }

  // ===== 替换 =====

  /**
   * 替换（replace）
   * @param {string|RegExp} 查找
   * @param {string|Function} 替换为
   * @returns {字符串}
   */
  替换(查找, 替换为) {
    this._值 = this._值.replace(查找, 替换为);
    return this;
  }

  /**
   * 替换所有（replaceAll）
   * @param {string|RegExp} 查找
   * @param {string|Function} 替换为
   * @returns {字符串}
   */
  替换所有(查找, 替换为) {
    if (typeof this._值.replaceAll === "function") {
      this._值 = this._值.replaceAll(查找, 替换为);
    } else {
      // fallback: 全局正则或 split/join
      if (查找 instanceof RegExp) {
        const flags = 查找.flags.includes("g") ? 查找.flags : 查找.flags + "g";
        const g = new RegExp(查找.source, flags);
        this._值 = this._值.replace(g, 替换为);
      } else {
        this._值 = this._值.split(String(查找)).join(String(替换为));
      }
    }
    return this;
  }

  // ===== 截取 / 切分 =====

  /**
   * 截取子串（substring）
   * @param {number} 开始
   * @param {number} [结束]
   * @returns {字符串}
   */
  取子串(开始, 结束) {
    this._值 = this._值.substring(开始, 结束);
    return this;
  }

  /**
   * 取片段（slice）
   * @param {number} 开始
   * @param {number} [结束]
   * @returns {字符串}
   */
  取子片段(开始, 结束) {
    this._值 = this._值.slice(开始, 结束);
    return this;
  }

  /**
   * 截取（substr - 旧）
   * @param {number} 起始
   * @param {number} [长度]
   * @returns {字符串}
   */
  截取(起始, 长度) {
    this._值 = this._值.substr(起始, 长度);
    return this;
  }

  /**
   * 拆分为数组（split）
   * @param {string|RegExp} 分隔符
   * @param {number} [限制]
   * @returns {string[]}
   */
  拆分(分隔符, 限制) {
    return this._值.split(分隔符, 限制);
  }

  /**
   * 按行拆分（保留空行）
   * @returns {string[]}
   */
  拆分为行() {
    return this._值.split(/\r\n|\n|\r/);
  }

  // ===== 字符 / 编码 =====

  /**
   * 取字符（charAt）
   * @param {number} 位置
   * @returns {string}
   */
  取字符(位置) {
    return this._值.charAt(位置);
  }

  /**
   * 取编码（charCodeAt）
   * @param {number} 位置
   * @returns {number}
   */
  取编码(位置) {
    return this._值.charCodeAt(位置);
  }

  /**
   * 取码点（codePointAt）
   * @param {number} 位置
   * @returns {number|undefined}
   */
  码点取字符(位置) {
    return this._值.codePointAt(位置);
  }

  /**
   * 静态：从编码创建字符串（fromCharCode）
   * @param {...number} 码
   * @returns {字符串}
   */
  static 从编码(...码) {
    return new 字符串(String.fromCharCode(...码));
  }

  /**
   * 静态：从码点创建字符串（fromCodePoint）
   * @param {...number} 码点
   * @returns {字符串}
   */
  static 从码点(...码点) {
    return new 字符串(String.fromCodePoint(...码点));
  }

  // ===== Unicode / Normalization =====

  /**
   * 归一化（normalize）
   * @param {"NFC"|"NFD"|"NFKC"|"NFKD"} [形式="NFC"]
   * @returns {字符串}
   */
  归一化(形式 = "NFC") {
    this._值 = this._值.normalize(形式);
    return this;
  }

  // ===== 填充 =====

  /**
   * 左填充（padStart）
   * @param {number} 长度
   * @param {string} [填充符=" "]
   * @returns {字符串}
   */
  填充前(长度, 填充符 = " ") {
    this._值 = this._值.padStart(长度, 填充符);
    return this;
  }

  /**
   * 右填充（padEnd）
   * @param {number} 长度
   * @param {string} [填充符=" "]
   * @returns {字符串}
   */
  填充后(长度, 填充符 = " ") {
    this._值 = this._值.padEnd(长度, 填充符);
    return this;
  }

  // ===== 大小写 / 本地化 =====

  /**
   * 转为本地小写（toLocaleLowerCase）
   * @param {...any} args
   * @returns {字符串}
   */
  本地小写(...args) {
    this._值 = this._值.toLocaleLowerCase(...args);
    return this;
  }

  /**
   * 转为本地大写（toLocaleUpperCase）
   * @param {...any} args
   * @returns {字符串}
   */
  本地大写(...args) {
    this._值 = this._值.toLocaleUpperCase(...args);
    return this;
  }

  // ===== 兼容 / 现代方法 =====

  /**
   * at 方法（支持负索引）
   * @param {number} 索引
   * @returns {string}
   */
  at(索引) {
    if (typeof this._值.at === "function") return this._值.at(索引);
    const i = 索引 < 0 ? this._值.length + 索引 : 索引;
    return this._值.charAt(i);
  }

  /**
   * startsWith（别名）
   * @param {string} 前缀
   * @param {number} [起始]
   * @returns {boolean}
   */
  startsWith(前缀, 起始) {
    return this._值.startsWith(前缀, 起始);
  }

  /**
   * endsWith（别名）
   * @param {string} 后缀
   * @param {number} [长度]
   * @returns {boolean}
   */
  endsWith(后缀, 长度) {
    return this._值.endsWith(后缀, 长度);
  }

  /**
   * includes（别名）
   * @param {string} 子串
   * @param {number} [起始]
   * @returns {boolean}
   */
  includes(子串, 起始) {
    return this._值.includes(子串, 起始);
  }

  // ===== DOM 老 API（HTML 字符串装饰 - 保留） =====
  // 这些方法返回一个新的字符串（非链式），因为它们产生 HTML 包裹文本

  /**
   * 包装锚点（anchor）
   * @param {string} 名称
   * @returns {string}
   */
  锚点(名称) {
    return this._值.anchor ? this._值.anchor(名称) : `<a name="${名称}">${this._值}</a>`;
  }

  /**
   * bold -> 粗体
   * @returns {string}
   */
  粗体() {
    return this._值.bold ? this._值.bold() : `<b>${this._值}</b>`;
  }

  /**
   * italics -> 斜体
   * @returns {string}
   */
  斜体() {
    return this._值.italics ? this._值.italics() : `<i>${this._值}</i>`;
  }

  /**
   * small -> 小字
   * @returns {string}
   */
  小字() {
    return this._值.small ? this._值.small() : `<small>${this._值}</small>`;
  }

  /**
   * strike -> 删除线
   * @returns {string}
   */
  删除线() {
    return this._值.strike ? this._值.strike() : `<strike>${this._值}</strike>`;
  }

  /**
   * sub -> 下标
   * @returns {string}
   */
  下标() {
    return this._值.sub ? this._值.sub() : `<sub>${this._值}</sub>`;
  }

  /**
   * sup -> 上标
   * @returns {string}
   */
  上标() {
    return this._值.sup ? this._值.sup() : `<sup>${this._值}</sup>`;
  }

  // ===== 扩展实用方法（提升到 80+ 方法） =====

  /**
   * 转为驼峰（camelCase）
   * @returns {字符串}
   */
  驼峰() {
    this._值 = this._值
      .replace(/[_-]+/g, " ")
      .trim()
      .toLowerCase()
      .replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) =>
        index === 0 ? word.toLowerCase() : word.toUpperCase()
      )
      .replace(/\s+/g, "");
    return this;
  }

  /**
   * 转为帕斯卡（PascalCase）
   * @returns {字符串}
   */
  帕斯卡() {
    this._值 = this._值
      .replace(/[_-]+/g, " ")
      .trim()
      .toLowerCase()
      .replace(/(?:^\w|[A-Z]|\b\w)/g, (word) => word.toUpperCase())
      .replace(/\s+/g, "");
    return this;
  }

  /**
   * 转为下划线 snake_case
   * @returns {字符串}
   */
  下划线() {
    this._值 =
      this._值
        .replace(/([a-z])([A-Z])/g, "$1_$2")
        .replace(/[\s-]+/g, "_")
        .toLowerCase();
    return this;
  }

  /**
   * 转为中划线 kebab-case
   * @returns {字符串}
   */
  中划线() {
    this._值 =
      this._值
        .replace(/([a-z])([A-Z])/g, "$1-$2")
        .replace(/[\s_]+/g, "-")
        .toLowerCase();
    return this;
  }

  /**
   * 转为标题（Title Case）
   * @returns {字符串}
   */
  标题式() {
    this._值 = this._值
      .toLowerCase()
      .split(/\s+/)
      .map((w) => (w.length ? w[0].toUpperCase() + w.slice(1) : ""))
      .join(" ");
    return this;
  }

  /**
   * 去除所有空格（包括中间）
   * @returns {字符串}
   */
  去除所有空格() {
    this._值 = this._值.replace(/\s+/g, "");
    return this;
  }

  /**
   * 将字符串转为数组（按字符）
   * @returns {string[]}
   */
  转为数组() {
    return Array.from(this._值);
  }

  /**
   * 将字符串转为 JSON（尝试 parse）
   * @returns {any}
   */
  转为JSON() {
    try {
      return JSON.parse(this._值);
    } catch (e) {
      return null;
    }
  }

  /**
   * 从 JSON 载入（parse 并覆盖当前值）
   * @returns {字符串}
   */
  从JSON() {
    try {
      const v = JSON.parse(this._值);
      this._值 = typeof v === "string" ? v : JSON.stringify(v);
    } catch (e) {
      // ignore
    }
    return this;
  }

  /**
   * URL 编码
   * @returns {字符串}
   */
  编码URI() {
    this._值 = encodeURI(this._值);
    return this;
  }

  /**
   * URL 编码组件（encodeURIComponent）
   * @returns {字符串}
   */
  编码URI组件() {
    this._值 = encodeURIComponent(this._值);
    return this;
  }

  /**
   * URL 解码（decodeURI）
   * @returns {字符串}
   */
  解码URI() {
    this._值 = decodeURI(this._值);
    return this;
  }

  /**
   * URL 解码组件（decodeURIComponent）
   * @returns {字符串}
   */
  解码URI组件() {
    this._值 = decodeURIComponent(this._值);
    return this;
  }

  /**
   * Base64 编码（btoa, 浏览器环境）
   * @returns {字符串}
   */
  编码Base64() {
    if (typeof btoa === "function") {
      this._值 = btoa(this._值);
    } else if (typeof Buffer !== "undefined") {
      this._值 = Buffer.from(this._值, "utf8").toString("base64");
    }
    return this;
  }

  /**
   * Base64 解码（atob）
   * @returns {字符串}
   */
  解码Base64() {
    if (typeof atob === "function") {
      this._值 = atob(this._值);
    } else if (typeof Buffer !== "undefined") {
      this._值 = Buffer.from(this._值, "base64").toString("utf8");
    }
    return this;
  }

  /**
   * 填充并截断到指定宽度（常用于显示）
   * @param {number} 长度
   * @param {string} [填充符=' ']
   * @returns {字符串}
   */
  截断并填充(长度, 填充符 = " ") {
    if (this._值.length > 长度) {
      this._值 = this._值.slice(0, 长度);
    } else {
      this._值 = this._值.padEnd(长度, 填充符);
    }
    return this;
  }

  /**
   * 安全HTML转义
   * @returns {字符串}
   */
  转义HTML() {
    const map = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" };
    this._值 = this._值.replace(/[&<>"']/g, (m) => map[m]);
    return this;
  }

  /**
   * 反转义HTML
   * @returns {字符串}
   */
  反转义HTML() {
    const map = { "&amp;": "&", "&lt;": "<", "&gt;": ">", "&quot;": '"', "&#39;": "'" };
    this._值 = this._值.replace(/&(amp|lt|gt|quot|#39);/g, (m) => map[m]);
    return this;
  }

  /**
   * 计数某个子串出现次数（非重叠）
   * @param {string|RegExp} 子串
   * @returns {number}
   */
  计数(子串) {
    if (子串 instanceof RegExp) {
      const flags = 子串.flags.includes("g") ? 子串.flags : 子串.flags + "g";
      const g = new RegExp(子串.source, flags);
      const m = this._值.match(g);
      return m ? m.length : 0;
    } else {
      if (子串 === "") return 0;
      return this._值.split(子串).length - 1;
    }
  }

  /**
   * 截取并返回原字符串（非链式） - 获取并保留当前值的拷贝
   * @returns {string}
   */
  拿到并保留() {
    return this._值;
  }

  /**
   * 替换空白为单个空格
   * @returns {字符串}
   */
  合并空白() {
    this._值 = this._值.replace(/\s+/g, " ").trim();
    return this;
  }

  /**
   * 是否以英文单词边界分词包含（简单）
   * @param {string} 单词
   * @returns {boolean}
   */
  包含单词(单词) {
    const re = new RegExp(`\\b${单词.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`);
    return re.test(this._值);
  }

  /**
   * 忽略大小写包含
   * @param {string} 子串
   * @returns {boolean}
   */
  包含_忽略大小写(子串) {
    return this._值.toLowerCase().includes(String(子串).toLowerCase());
  }

  /**
   * 忽略大小写替换（所有）
   * @param {string} 查找
   * @param {string} 替换为
   * @returns {字符串}
   */
  替换_忽略大小写_所有(查找, 替换为) {
    const re = new RegExp(查找.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "gi");
    this._值 = this._值.replace(re, 替换为);
    return this;
  }

  /**
   * 将多个空白行合并为一个空行
   * @returns {字符串}
   */
  合并空行() {
    this._值 = this._值.replace(/\n{2,}/g, "\n\n");
    return this;
  }

  /**
   * 将字符串按固定宽度换行（简单实现，不考虑单词完整性）
   * @param {number} 宽度
   * @returns {字符串}
   */
  换行(宽度) {
    const regex = new RegExp(`(.{1,${宽度}})`, "g");
    this._值 = this._值.match(regex)?.join("\n") ?? this._值;
    return this;
  }

  /**
   * 移除前后指定字符（如双引号）
   * @param {string} 字符
   * @returns {字符串}
   */
  去除引号(字符 = '"') {
    const esc = 字符.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
    this._值 = this._值.replace(new RegExp(`^${esc}|${esc}$`, "g"), "");
    return this;
  }

  /**
   * 用函数映射每个字符并生成新字符串
   * @param {(ch:string, idx:number)=>string} fn
   * @returns {字符串}
   */
  映射字符(fn) {
    this._值 = Array.from(this._值)
      .map((ch, i) => fn(ch, i))
      .join("");
    return this;
  }

  /**
   * 将每个单词首字母大写（每个由空白分隔的词）
   * @returns {字符串}
   */
  单词首字母大写() {
    this._值 = this._值.replace(/\b\w/g, (m) => m.toUpperCase());
    return this;
  }

  /**
   * 移除指定前缀（如存在）
   * @param {string} 前缀
   * @returns {字符串}
   */
  移除前缀(前缀) {
    if (this._值.startsWith(前缀)) this._值 = this._值.slice(前缀.length);
    return this;
  }

  /**
   * 移除指定后缀（如存在）
   * @param {string} 后缀
   * @returns {字符串}
   */
  移除后缀(后缀) {
    if (this._值.endsWith(后缀)) this._值 = this._值.slice(0, -后缀.length);
    return this;
  }

  /**
   * 安全构造正则（Escape）
   * @returns {字符串}
   */
  转义正则() {
    this._值 = this._值.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
    return this;
  }

  /**
   * 以指定字符串为界取左侧（第一个出现之前）
   * @param {string} 分隔
   * @returns {字符串}
   */
  取左(分隔) {
    const i = this._值.indexOf(分隔);
    if (i === -1) return this;
    this._值 = this._值.slice(0, i);
    return this;
  }

  /**
   * 以指定字符串为界取右侧（第一个出现之后）
   * @param {string} 分隔
   * @returns {字符串}
   */
  取右(分隔) {
    const i = this._值.indexOf(分隔);
    if (i === -1) return this;
    this._值 = this._值.slice(i + 分隔.length);
    return this;
  }

  /**
   * 短化显示（中间省略）
   * @param {number} 左侧
   * @param {number} 右侧
   * @param {string} [省略符='...']
   * @returns {字符串}
   */
  中间省略(左侧 = 6, 右侧 = 6, 省略符 = "...") {
    if (this._值.length <= 左侧 + 右侧 + 省略符.length) return this;
    this._值 = this._值.slice(0, 左侧) + 省略符 + this._值.slice(-右侧);
    return this;
  }

  /**
   * 安全地将模板字符串中的花括号替换为占位符（避免模板注入）
   * @returns {字符串}
   */
  转义模板花括号() {
    this._值 = this._值.replace(/\$\{/, "\\${");
    return this;
  }

  /**
   * 将字符串与另一个字符串进行自然比较（数字按数值比较）
   * @param {string} 目标
   * @returns {number}
   */
  自然比较(目标) {
    // 简单实现：分割数字与非数字并逐段比较
    const split = (s) => s.match(/(\d+|\D+)/g) || [];
    const a = split(this._值);
    const b = split(String(目标));
    for (let i = 0; i < Math.max(a.length, b.length); i++) {
      if (a[i] === undefined) return -1;
      if (b[i] === undefined) return 1;
      const na = Number(a[i]);
      const nb = Number(b[i]);
      if (!Number.isNaN(na) && !Number.isNaN(nb)) {
        if (na !== nb) return na - nb;
      } else {
        if (a[i] !== b[i]) return a[i] < b[i] ? -1 : 1;
      }
    }
    return 0;
  }

  /**
   * 清空字符串（置为空串）
   * @returns {字符串}
   */
  清空() {
    this._值 = "";
    return this;
  }

  /**
   * 以 JSON.stringify 的方式设置当前值（并返回 this）
   * @param {any} v
   * @returns {字符串}
   */
  设置为JSON(v) {
    this._值 = JSON.stringify(v);
    return this;
  }

  /**
   * 安全截断指定字符长度（按字符，不按字节）
   * @param {number} 长度
   * @returns {字符串}
   */
  截断字符(长度) {
    this._值 = Array.from(this._值).slice(0, 长度).join("");
    return this;
  }

  /**
   * 用指定字符填充中间（比如表格居中显示）
   * @param {number} 宽度
   * @param {string} 填充符
   * @returns {字符串}
   */
  居中填充(宽度, 填充符 = " ") {
    const len = Array.from(this._值).length;
    if (len >= 宽度) return this;
    const 空余 = 宽度 - len;
    const 左 = Math.floor(空余 / 2);
    const 右 = 空余 - 左;
    this._值 = 填充符.repeat(左) + this._值 + 填充符.repeat(右);
    return this;
  }

  /**
   * 转换为布尔（仅当字符串为 "true" / "false"）
   * @returns {boolean|null}
   */
  转为布尔() {
    const v = this._值.trim().toLowerCase();
    if (v === "true") return true;
    if (v === "false") return false;
    return null;
  }

  /**
   * 加密占位（简单md5占位）- 注意：仅示例（非安全）
   * @returns {字符串}
   */
  简易哈希() {
    let h = 0;
    for (let i = 0; i < this._值.length; i++) {
      h = (h << 5) - h + this._值.charCodeAt(i);
      h |= 0;
    }
    this._值 = String(Math.abs(h));
    return this;
  }

  /**
   * 将路径分隔符统一为 '/'
   * @returns {字符串}
   */
  统一路径分隔() {
    this._值 = this._值.replace(/\\/g, "/");
    return this;
  }

  /**
   * 以某个分隔符重复拼接 n 次
   * @param {string} 分隔符
   * @param {number} 次数
   * @returns {字符串}
   */
  重复拼接(分隔符, 次数) {
    if (次数 <= 0) {
      this._值 = "";
      return this;
    }
    this._值 = Array(次数).fill(this._值).join(分隔符);
    return this;
  }

  /**
   * 安全替换模板中的变量（object -> 替换 ${key}）
   * @param {Object} map
   * @returns {字符串}
   */
  模板替换(map) {
    this._值 = this._值.replace(/\$\{([^}]+)\}/g, (m, key) => {
      const v = map[key];
      return v === undefined ? "" : String(v);
    });
    return this;
  }

  /**
   * 转换为查询字符串（a=1&b=2）- 简单实现，假定当前字符串为 JSON 对象或 query-like
   * @returns {字符串}
   */
  转为查询字符串() {
    try {
      const obj = JSON.parse(this._值);
      if (typeof obj === "object" && obj !== null) {
        const parts = [];
        for (const k of Object.keys(obj)) {
          parts.push(encodeURIComponent(k) + "=" + encodeURIComponent(String(obj[k])));
        }
        this._值 = parts.join("&");
      }
    } catch (e) {
      // ignore
    }
    return this;
  }

  /**
   * 将 querystring 解析为对象（非链式）
   * @returns {Object}
   */
  解析查询字符串() {
    const s = this._值.replace(/^\?/, "");
    const parts = s.split("&").filter(Boolean);
    const out = {};
    for (const p of parts) {
      const [k, v = ""] = p.split("=");
      out[decodeURIComponent(k)] = decodeURIComponent(v);
    }
    return out;
  }

  /**
   * 获取文件扩展名（不包括点）
   * @returns {string}
   */
  文件扩展名() {
    const m = this._值.match(/\.([^.\/\\]+)$/);
    return m ? m[1] : "";
  }

  /**
   * 获取文件名（不含路径）
   * @returns {string}
   */
  文件名() {
    const parts = this._值.replace(/\\/g, "/").split("/");
    return parts[parts.length - 1];
  }

  /**
   * 省略末尾特定字符（如多个换行）
   * @param {string|RegExp} ch
   * @returns {字符串}
   */
  省略末尾(ch) {
    if (ch instanceof RegExp) {
      this._值 = this._值.replace(new RegExp("(" + ch.source + ")+$"), "");
    } else {
      const esc = String(ch).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
      this._值 = this._值.replace(new RegExp("(" + esc + ")+$"), "");
    }
    return this;
  }
}


// 同时支持 ES 模块和 CommonJS 导出
try {
  // 浏览器环境导出
  if (typeof exports === 'undefined') {
    window.字符串 = 字符串;
  }
} catch (e) {}

// CommonJS 导出

  module.exports = {
    字符串,
    default: 字符串
  };
  module.exports.字符串 = 字符串;


// ES 模块导出
// export { 字符串 };
// export default 字符串;